﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace DynaSpace.Entity
{
	/// <summary>
	/// Abstraktní třída reprezentující objekt ve hře (na mapě)
	/// </summary>
	public abstract class EntityBase
	{
		private Vector2 position;
		private Playground parent;

		/// <summary>
		/// Šířka pole v pixelech
		/// </summary>
		public const float SIZEX = 32;

		/// <summary>
		/// Výška pole v pixelech
		/// </summary>
		public const float SIZEY = 34;

		/// <summary>
		/// Velikost pole v pixelech
		/// </summary>
		public static readonly Vector2 SIZE = new Vector2(SIZEX, SIZEY);

		/// <summary>
		/// Vytvoří nový <see cref="EntityBase"/>
		/// </summary>
		/// <param name="parent"><see cref="EntityCollection">Kolekce</see>, do které bude spadat vytvářený <see cref="EntityBase"/>.</param>
		/// <param name="position">Počáteční pozice entity</param>
		public EntityBase(Playground parent, Vector2 position)
		{
			this.parent = parent;
			this.position = position;
			this.Size = Vector2.One;
		}

		/// <summary>
		/// Smaže z mapy a odstraní návaznosti na entitu
		/// </summary>
		public virtual void Delete()
		{
			parent.Map.Remove(this);
		}

		/// <summary>
		/// Znovu přidá do kolekcí instanci
		/// </summary>
		public virtual void AddAgain()
		{
			parent.Map.Add(this);
		}

		/// <summary>
		/// Vrací rodičovský <see cref="Playground"/>
		/// </summary>
		public Playground Parent
		{
			get
			{
				return parent;
			}
		}

		/// <summary>
		/// Vrací nebo nastavuje pozici objektu na mapě
		/// </summary>
		public Vector2 Position
		{
			get
			{
				return position;
			}
			set
			{
				if (!position.Equals(value))
				{
					// pokud se změnil změnou pozice i sektor, odregistrujeme a zase zaregistrujeme entitu
					bool sectorChanged = position.InDiffSector(value);

					if (sectorChanged) // při změně sektoru nejdříve entitu odebrat
						parent.Map.Remove(this);

					position = value; // zmenit pozici

					if (sectorChanged) // následně zase přidat
						parent.Map.Add(this);
				}
			}
		}

		/// <summary>
		/// Vrací nebo nastavuje velikost entity.
		/// Defaultně 1x1
		/// </summary>
		public Vector2 Size
		{
			get;
			protected set;
		}

		/// <summary>
		/// Vrací, zda se aktuální entita překrývá s jinou entitou
		/// </summary>
		/// <param name="entity"><see cref="EntityBase"/> na kontrolu</param>
		/// <returns>Vrací, zda se entity překrývají</returns>
		public bool IsIntersecting(EntityBase entity)
		{
			return IsIntersecting(entity.position, entity.Size);
		}

		/// <summary>
		/// Vrací, zda se aktuální entita překrývá s jinou entitou
		/// </summary>
		/// <param name="position">Pozice entity pro kontrolu</param>
		/// <param name="size">Velikost entity (implicitně hodnota 1x1)</param>
		/// <returns>Vrací, zda se entity překrývají</returns>
		public bool IsIntersecting(Vector2 position, Vector2 size)
		{
			float widthSpace = (1 - size.X) / 2;
			float heightSpace = (1 - size.Y) / 2;

			return (
				this.Position.X + 1 >= position.X + widthSpace
				&& this.position.Y + 1 >= position.Y + heightSpace
				&& this.position.X < position.X + 1 - widthSpace 
				&& this.position.Y < position.Y + 1 - heightSpace 
				);
		}

		/// <summary>
		/// Vrací, zda má entita kolizi s předanou entitou.
		/// </summary>
		/// <param name="entity">Entita, které se zjištujě, zda má kolizi s aktuální entitou.</param>
		/// <param name="position">Pozice, na které se bude hledat kolize (může to být toereticky nová pozice předané entity).</param>
		/// <returns>Vrací, zda má předaná entita kolizi s aktuální entitou.</returns>
		public bool IsCollision(EntityBase entity, Vector2 position)
		{
			if (this is ICollision)
				return IsIntersecting(position, entity.Size) && (this as ICollision).CanCollide(entity);

			return false;
		}
	}
}
